﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace S7Helper
{
    public static class S7API
    {
        private static S7Client Client;
        /// <summary>
        /// 建立PLC连接
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool Connect(string ip)
        {
            try
            {
                Client = new S7Client();
                // Create and connect the client
                int result = Client.ConnectTo(ip, 0, 1);

                if (result == 0)
                {
                    return true;
                }
                else
                {

                    return false;
                }
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }
        /// <summary>
        /// 断开PLC连接
        /// </summary>
        public static void DisConnect()
        {
            try
            {
                // Disconnect the client
                Client?.Disconnect();
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }

        #region DataBlock
        /// <summary>
        /// 读取Int类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <returns></returns>
        public static int ReadInt(string address)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("ReadInt,地址格式不正确");
                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                var result = Client.DBRead(addressDB, startByteAdr, 4, buffer);
                if (result != 0) throw new Exception("ReadInt failed");
                var readInt = S7.GetDIntAt(buffer, 0);
                return readInt;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 写入Int类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <param name="value"></param>
        public static int WriteInt(string address, int value)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("WriteInt,地址格式不正确");
                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                S7.SetDIntAt(buffer, 0, value);
                var result = Client.DBWrite(addressDB, startByteAdr, 4, buffer);
                return result;
                if (result != 0) throw new Exception("WriteInt failed");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 写入Byte类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <param name="value"></param>
        public static int WriteByte(string address, byte value)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("WriteBtye,地址格式不正确");
                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                S7.SetByteAt(buffer, 0, value);
                var result = Client.DBWrite(addressDB, startByteAdr, 1, buffer);
                return result;
                if (result != 0) throw new Exception("WriteBtye failed");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 读取Byte类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <returns></returns>
        public static byte ReadByte(string address)
        {
            try
            {
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                int addressDB = 0;
                int startByteAdr = 0;
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("ReadBtye,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);
                byte[] buffer = new byte[8];
                var result = Client.DBRead(addressDB, startByteAdr, 1, buffer);
                if (result != 0) throw new Exception("ReadBtye failed");
                var readByte = S7.GetByteAt(buffer, 0);
                return readByte;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 写入Float类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <param name="value"></param>
        public static int WriteFloat(string address, float value)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("WriteFloat,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                S7.SetRealAt(buffer, 0, value);
                var result = Client.DBWrite(addressDB, startByteAdr, 4, buffer);
                return result;
                if (result != 0) throw new Exception("WriteFloat failed");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 读取Float类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <returns></returns>
        public static float ReadFloat(string address)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("ReadFloat,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                var result = Client.DBRead(addressDB, startByteAdr, 4, buffer);
                if (result != 0) throw new Exception("ReadFloat failed");
                var readByte =S7.GetRealAt(buffer, 0);
                return readByte;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 写入Double类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <param name="value"></param>
        public static int WriteDouble(string address, double value)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("WriteDouble,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                S7.SetLRealAt(buffer, 0, value);
                var result = Client.DBWrite(addressDB, startByteAdr, 8, buffer);
                return result;
                if (result != 0) throw new Exception("WriteDouble failed");

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 读取Double类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <returns></returns>
        public static double ReadDouble(string address)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("ReadDouble,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                var result = Client.DBRead(addressDB, startByteAdr, 8, buffer);
                if (result != 0) throw new Exception("ReadDouble failed");

                var readByte =S7.GetLRealAt(buffer, 0);
                return readByte;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 写入Bool类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <param name="value"></param>
        public static int WriteBool(string address, bool value)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("WriteBool,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                S7.SetBitAt(ref buffer, 0, 1, value);
                var result = Client.DBWrite(addressDB, startByteAdr, 8, buffer);
                return result;
                if (result != 0) throw new Exception("WriteBool failed");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 读取Bool类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <returns></returns>
        public static bool ReadBool(string address)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("ReadBool,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                var result = Client.DBRead(addressDB, startByteAdr, 1, buffer);
                if (result != 0) throw new Exception("ReadBool failed");
                var readByte = S7.GetBitAt(buffer, 0, 1);
                return readByte;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 写入String类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <param name="value"></param>
        public static int WriteString(string address, string value)
        {
            try
            {
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("WriteString,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                //转码后的真实数据长度
                var length = Encoding.UTF8.GetBytes(value).Length;
                //转码后的真实数据长度 + 2个提示位的总长度
                // 2个提示位：buffer[0]是最大字符串长度，默认为254；buffer[1]是有效的字符串长度4
                int byteLength = length + 2;
                byte[] buffer = new byte[byteLength];
                S7.SetStringAt(buffer, 0, 254, value, length);
                var result = Client.DBWrite(addressDB, startByteAdr, byteLength, buffer);
                return result;
                if (result != 0) throw new Exception("WriteString failed");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 读取String类型数据
        /// </summary>
        /// <param name="addressDB"></param>
        /// <param name="startByteAdr"></param>
        /// <returns></returns>
        public static string ReadString(string address)
        {
            try
            {
                byte[] buffer = new byte[8];
                int addressDB = 0;
                int startByteAdr = 0;
                var addressRegex = Regex.Match(address, @"DB(\d+)\.(\d+)");
                if (string.IsNullOrEmpty(addressRegex.Value)) throw new Exception("WriteString,地址格式不正确");

                addressDB = int.Parse(addressRegex?.Groups[1].Value);
                startByteAdr = int.Parse(addressRegex?.Groups[2].Value);

                var result = Client.DBRead(addressDB, startByteAdr, 2, buffer);
                if (result != 0) throw new Exception("ReadString failed");

                //真实的数据长度
                var stringLength = buffer[1];
                //真实的数据长度 + 2个提示位的总长度
                // 2个提示位：buffer[0]是最大字符串长度，默认为254；buffer[1]是有效的字符串长度4
                int byteLength = stringLength + 2;
                var bufferString = new byte[byteLength];
                result = Client.DBRead(addressDB, startByteAdr, byteLength, bufferString);
                if (result != 0) throw new Exception("ReadString failed");
                var readByte = S7.GetStringAt(bufferString, 0);
                return readByte;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

    }
}
